#include "ptrace_utils.h"

int trace_read_data(pid_t pid, unsigned long addr, void *vptr, int len)
{
    int i, count;
    long word;
    unsigned long *ptr = (unsigned long *) vptr;
    errno = count = i = 0;
    while (count < len) {
        word = ptrace(PTRACE_PEEKTEXT, pid, addr + count, NULL);
        if (errno != 0) {
            perror("trace_read_data");
            break;
        }
        count += 4;
        ptr[i++] = word;
    }
    return errno;
}

int trace_write_data(pid_t pid, unsigned long addr, void *vptr, int len)
{
    int count;
    long word;
    errno = count = 0;
    while (count < len) {
        memcpy(&word, vptr + count, sizeof(word));
        word = ptrace(PTRACE_POKETEXT, pid, addr + count, word);
        if (errno != 0) {
            perror("trace_write_data");
            break;
        }
        count += 4;
    }
    return errno;
}

void print_regsisters(struct user_regs_struct *regs)
{
    printf("eax %08lx\n", regs->eax);
    printf("ebp %08lx\n", regs->ebp);
    printf("ebx %08lx\n", regs->ebx);
    printf("ecx %08lx\n", regs->ecx);
    printf("edi %08lx\n", regs->edi);
    printf("edx %08lx\n", regs->edx);
    printf("eflags %08lx\n", regs->eflags);
    printf("eip %08lx\n", regs->eip);
    printf("esi %08lx\n", regs->esi);
    printf("esp %08lx\n", regs->esp);
    printf("orig_eax %d\n", (int)regs->orig_eax);
    printf("xcs %08lx\n", regs->xcs);
    printf("xds %08lx\n", regs->xds);
    printf("xes %08lx\n", regs->xes);
    printf("xfs %08lx\n", regs->xfs);
    printf("xgs %08lx\n", regs->xgs);
    printf("xss %08lx\n\n", regs->xss);
}

int trace_get_regs(pid_t pid, struct user_regs_struct *regs)
{
    if (ptrace(PTRACE_GETREGS, pid, NULL, regs) < 0) {
        perror("trace_get_regs");
        return errno;
    }
    printf("\nget_regs\n");
    print_regsisters(regs);
    return 0;
}

int trace_set_regs(pid_t pid, struct user_regs_struct *regs)
{
    if (ptrace(PTRACE_SETREGS, pid, NULL, regs) < 0) {
        perror("trace_set_regs");
        return errno;
    }
    printf("\nset_regs\n");
    print_regsisters(regs);
    return 0;
}

int trace_cont(pid_t pid, int* status)
{
    if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0 || waitpid(pid, status, 0) < 0) {
        perror("trace_cont");
        return errno;
    }
    return 0;
}

int trace_get_siginfo(pid_t pid, siginfo_t* siginfo)
{
    if ( ptrace (PTRACE_GETSIGINFO, pid, 0, siginfo) < 0) {
        perror("trace_get_siginfo");
        return errno;
    }
    return 0;
}
